package kdt

import (
	"encoding/json"
	"errors"
	"fmt"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"
)

func PackAdd(w http.ResponseWriter, r *http.Request) {
	crossDomain(w)
	p := Pack{} //ProductId,Owner:sid,Num:1
	b, _ := ioutil.ReadAll(r.Body)
	e := json.Unmarshal(b, &p)
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	u, e := getUserBySid(p.Owner)
	if e != nil {
		ReturnInfo(w, "ERR", "sid expired")
		return
	}
	p.Owner = u.Phone
	product, e := getProductById(p.ProductId)
	if e != nil {
		ReturnInfo(w, "ERR", "product doesn't exists")
		return
	}
	if p.Num < 1 {
		ReturnInfo(w, "ERR", "number invalid")
		return
	}
	p.PackId = NewToken()
	p.Title = product.Title
	e = addPack(p)
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	ReturnInfo(w, "OK", p.PackId)
}
func PackUserReceive(w http.ResponseWriter, r *http.Request) {
	crossDomain(w)
	m := Msg{} //State:UserSid, Info:PackId
	b, _ := ioutil.ReadAll(r.Body)
	e := json.Unmarshal(b, &m)
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	u, e := getUserBySid(m.State)
	if e != nil {
		ReturnInfo(w, "ERR", "sid expired")
		return
	}
	p, e := getPackByPackId(m.Info)
	if e != nil {
		ReturnInfo(w, "ERR", "pack doesn't exists")
		return
	}
	if p.Owner != u.Phone {
		ReturnInfo(w, "ERR", "permission denied")
		return
	}
	if p.PackState {
		ReturnInfo(w, "ERR", "already recieved")
		return
	}
	p.PackState = true
	e = updatePack(p.PackId, p)
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	ReturnInfo(w, "OK", p.PackId)
}
func PackAdminQueryUnclaimedPack(w http.ResponseWriter, r *http.Request) {
	crossDomain(w)
	m := Msg{} //Info:pageNum
	b, _ := ioutil.ReadAll(r.Body)
	e := json.Unmarshal(b, &m)
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	page, e := strconv.Atoi(m.Info)
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	var BackData struct {
		State, Info string
		Ps          []Pack
		Count       int
	}
	BackData.Ps, BackData.Count, e = getUnclaimedPacks(page)
	if e != nil {
		if BackData.Count == 0 {
			ReturnInfo(w, "ERR", "no packs yet")
			return
		}
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	BackData.State = "OK"
	ReturnData(w, BackData)
}
func PackAdminQuery(w http.ResponseWriter, r *http.Request) {
	crossDomain(w)
	m := Msg{} //State:AdminSid
	b, _ := ioutil.ReadAll(r.Body)
	e := json.Unmarshal(b, &m)
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	admin, e := getAdminBySid(m.State)
	if e != nil {
		ReturnInfo(w, "ERR", "sid expired")
		return
	}
	s, e := mgo.Dial(MongoDBServer)
	if e != nil {
		fmt.Println(e)
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	defer s.Close()
	var backData struct {
		State string
		Ps    []Pack
	}
	e = s.DB("kdt").C("packs").Find(bson.M{"admin": admin.Phone, "packstate": false}).All(&backData.Ps)
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	backData.State = "OK"
	ReturnData(w, backData)
}
func PackAdminClaim(w http.ResponseWriter, r *http.Request) {
	crossDomain(w)
	m := Msg{} //State:AdminSid , Info:PackId
	b, _ := ioutil.ReadAll(r.Body)
	e := json.Unmarshal(b, &m)
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	admin, e := getAdminBySid(m.State)
	if e != nil {
		ReturnInfo(w, "ERR", "sid expired")
		return
	}
	p, e := getPackByPackId(m.Info)
	if e != nil {
		ReturnInfo(w, "ERR", "no such pack")
		return
	}
	p.Admin = admin.Phone
	e = updatePack(p.PackId, p)
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	ReturnInfo(w, "OK", p.PackId)
}
func PackUserQuery(w http.ResponseWriter, r *http.Request) {
	crossDomain(w)
	m := Msg{} //State:UserSid ,Info:filter
	b, _ := ioutil.ReadAll(r.Body)
	e := json.Unmarshal(b, &m)
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	u, e := getUserBySid(m.State)
	if e != nil {
		ReturnInfo(w, "ERR", "sid expired")
		return
	}
	var backData struct {
		State string
		Ps    []Pack
	}
	switch m.Info {
	case "unreceived":
		backData.Ps, e = getUnreceivedPacksByPhone(u.Phone)
	case "received":
		backData.Ps, e = getReceivedPacksByPhone(u.Phone)
	case "all":
		backData.Ps, e = getPacksByPhone(u.Phone)
	default:
		ReturnInfo(w, "ERR", "no such filter")
		return
	}
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	backData.State = "OK"
	ReturnData(w, backData)
}
func PackQuery(w http.ResponseWriter, r *http.Request) {
	crossDomain(w)
	m := Msg{} //State:PackId
	b, _ := ioutil.ReadAll(r.Body)
	e := json.Unmarshal(b, &m)
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	var backData struct {
		State string
		P     Pack
	}
	backData.P, e = getPackByPackId(m.State)
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	backData.State = "OK"
	ReturnData(w, backData)
}
func PackAdminAddDeliveryDot(w http.ResponseWriter, r *http.Request) {
	crossDomain(w)
	m := Msg{} //State:AdminSid , Info:PackId , Other:DotTitle
	b, _ := ioutil.ReadAll(r.Body)
	e := json.Unmarshal(b, &m)
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	admin, e := getAdminBySid(m.State)
	if e != nil {
		ReturnInfo(w, "ERR", "sid expired")
		return
	}
	p, e := getPackByPackId(m.Info)
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	if p.PackState {
		ReturnInfo(w, "ERR", "pack already received")
		return
	}
	if p.Admin == "" {
		ReturnInfo(w, "ERR", "plz claim first")
		return
	}
	if p.Admin != "" && p.Admin != admin.Phone {
		ReturnInfo(w, "ERR", "permission denied")
		return
	}
	p.DeliveryDots = append(p.DeliveryDots, Dot{Title: m.Other, Time: time.Now()})
	e = updatePack(p.PackId, p)
	if e != nil {
		ReturnInfo(w, "ERR", e.Error())
		return
	}
	ReturnInfo(w, "OK", p.PackId)
}
func addPack(p Pack) error {
	p.PackState = false
	p.DeliveryDots = nil
	p.Admin = ""
	s, e := mgo.Dial(MongoDBServer)
	if e != nil {
		fmt.Println(e)
		return e
	}
	defer s.Close()
	e = s.DB("kdt").C("packs").Insert(p)
	return e
}
func getUnclaimedPacks(page int) ([]Pack, int, error) {
	s, e := mgo.Dial(MongoDBServer)
	if e != nil {
		fmt.Println(e)
		return nil, -1, e
	}
	defer s.Close()
	count, _ := s.DB("kdt").C("packs").Find(bson.M{"admin": ""}).Count()
	if getPages(count) < page {
		return nil, count, errors.New("page not found")
	}
	ps := []Pack{}
	e = s.DB("kdt").C("packs").Find(bson.M{"admin": ""}).Limit(20).Skip((page - 1) * 20).All(&ps)
	if e != nil {
		return nil, count, e
	}
	return ps, count, nil
}

func getUnreceivedPacksByPhone(phone string) ([]Pack, error) {
	s, e := mgo.Dial(MongoDBServer)
	if e != nil {
		fmt.Println(e)
		return nil, e
	}
	defer s.Close()
	ps := []Pack{}
	e = s.DB("kdt").C("packs").Find(bson.M{"owner": phone, "packstate": false}).All(&ps)
	return ps, e
}

func getReceivedPacksByPhone(phone string) ([]Pack, error) {
	s, e := mgo.Dial(MongoDBServer)
	if e != nil {
		fmt.Println(e)
		return nil, e
	}
	defer s.Close()
	ps := []Pack{}
	e = s.DB("kdt").C("packs").Find(bson.M{"owner": phone, "packstate": true}).All(&ps)
	return ps, e
}

func getPacksByPhone(phone string) ([]Pack, error) {
	s, e := mgo.Dial(MongoDBServer)
	if e != nil {
		fmt.Println(e)
		return nil, e
	}
	defer s.Close()
	ps := []Pack{}
	e = s.DB("kdt").C("packs").Find(bson.M{"owner": phone}).All(&ps)
	return ps, e
}
func getPages(c int) int {
	page := c / 20
	if c%20 == 0 {
		return page
	}
	return page + 1
}
func getPackByPackId(id string) (Pack, error) {
	p := Pack{}
	s, e := mgo.Dial(MongoDBServer)
	if e != nil {
		fmt.Println(e)
		return p, e
	}
	defer s.Close()
	e = s.DB("kdt").C("packs").Find(bson.M{"packid": id}).One(&p)
	if e != nil {
		return p, e
	}
	return p, nil
}
func updatePack(packid string, p Pack) error {
	s, e := mgo.Dial(MongoDBServer)
	if e != nil {
		fmt.Println(e)
		return e
	}
	defer s.Close()
	e = s.DB("kdt").C("packs").Update(bson.M{"packid": packid}, &p)
	return e
}
